Release 10.1A: OpenEdge Getting Started:
Object-oriented Programming


Defining the class destructor

The destructor of a class is a special method that gets called when a class instance is deleted by a DELETE OBJECT statement. The destructor of a class has the same name as the class name. Unlike ordinary methods, a destructor is identified by the DESTRUCTOR keyword. Destructors have no return type and are always PUBLIC. A destructor cannot have any parameters.

A destructor can never be called directly; instead it is executed automatically by Progress when an object is deleted with the DELETE OBJECT statement. A class is not required to have a destructor. If a class has not defined a destructor for the class, Progress provides a default destructor for the class. As with persistent procedure instances and dynamic data objects, an application is responsible for deleting all class instances that are created by the application. This is done using the DELETE OBJECT statement for each class instance.

Progress does not automatically delete class instances until the entire Progress session ends. When an application exits a module or other part of the application where class instances have been used, it is your responsibility to delete all class instances that are still running but no longer needed. The destructor is responsible for deleting any resources allocated during the execution of the class instance. Deleting the class instance automatically deletes all dynamic objects that are created in the class instance's default unnamed widget pool. (For more information, see the "Using widget pools" section.) By deleting these objects, the application is ensuring not only that the resources allocated for the class instance itself are deleted, but also that the destructor for each of these objects is invoked.

When the session does end, Progress does not automatically run the destructor for any objects that have not been deleted by the application. Progress does automatically delete any Progress-related resources, such as persistent procedure and class instances, visual objects, and data objects. However, any other tasks that you have programmed in the destructor, such as writing to a log file, do not occur unless your application has explicitly deleted the associated object.

The DELETE OBJECT statement can already be used to delete dynamic visual and data objects as well as persistent procedure instances. What is different about classes with a destructor is that a class is given an opportunity to do necessary cleanup work when it is deleted. The value of the destructor is that it is executed automatically when the class instance is terminated using the DELETE OBJECT statement.

If a destructor fails to clean up the resources that were allocated for the object, there is no mechanism for it to inform the caller (the DELETE OBJECT statement) that it failed. It is illegal for a destructor to execute the RETURN ERROR statement to raise an error condition in the caller.

This is the syntax for defining a class destructor:

Syntax
DESTRUCTOR PUBLIC class-name ( ):  
    destructor-body 
END [ DESTRUCTOR ] . 

Element descriptions for this syntax diagram follow:

class-name

The name of the class stripped of any relative path information. This is the class-name portion of the type-name used in the CLASS statement.

destructor-body

The logic of the destructor and can be composed of any Progress statements allowed within a FUNCTION block plus new syntax that is permitted only in methods. The destructor logic is normally used to free up any dynamic objects or other system resources in use by the class.

Adding a destructor to the sample class definition results in the following code:

CLASS acme.myObjs.CustObj INHERITS acme.myObjs.Common.CommonObj:  
    DEFINE PUBLIC VARIABLE iNumCusts AS INTEGER NO-UNDO. 
    DEFINE PROTECTED TEMP-TABLE ttCust NO-UNDO 
        FIELD CustNum LIKE Customer.CustNum 
        FIELD Name LIKE Customer.Name. 
    DEFINE PRIVATE VARIABLE rError  
        AS CLASS acme.myObjs.Common.ErrorObj NO-UNDO. 
    CONSTRUCTOR PUBLIC CustObj( ): 
        iNumCusts = 0. 
        /* Fill temp table and get row count */ 
        FOR EACH Customer: 
            CREATE ttCust. 
            ASSIGN 
                ttCust.CustNum = Customer.CustNum 
                ttCust.Name = Customer.Name 
                iNumCusts = iNumCusts + 1. 
        END. 
        ... 
    END CONSTRUCTOR. 
    METHOD PUBLIC CHARACTER GetCustomerName(INPUT piCustNum AS INTEGER): 
        FIND ttCust WHERE ttCust.CustNum = piCustNum NO-ERROR. 
        IF AVAILABLE ttCust THEN 
            RETURN ttCust.CustName. 
        ELSE 
            RETURN ?. 
    END METHOD. 
    ... 
    DESTRUCTOR PUBLIC CustObj( ): 
        EMPTY TEMP-TABLE ttCust. 
        ... 
    END DESTRUCTOR. 
END CLASS. 

Comparison with procedure-based programming

With persistent procedures, the application must adhere to an enforced programming strategy in order to allow cleanup when the procedure exits. Typically, you do this by defining a trigger block to be executed ON CLOSE OF THIS-PROCEDURE, then take care to always delete a persistent procedure instance using the APPLY "CLOSE" statement rather than using the DELETE OBJECT statement. (This is the convention used in procedures generated by the AppBuilder.)

A destructor provides a uniform mechanism to handle such cleanup tasks in class-based objects without the need for special programming strategies.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095